xen: Automatically find serial port on PCI/PCIe and AMT devices.
authorJames Mckenzie <jamesmck@bob.uk.xensource.com>
Thu, 14 Jul 2011 08:28:23 +0000 (09:28 +0100)
committerJames Mckenzie <jamesmck@bob.uk.xensource.com>
Thu, 14 Jul 2011 08:28:23 +0000 (09:28 +0100)
Instead of having to manually look the right I/O port on the PCI
devices or AMT devices, lets probe the card and find that
automatically.

This means that you don't have to have this:
 com1=115200,8n1,0xd800,0

But instead can have
 com1=115200,8n1,magic

Or if you have AMT:
 com1=19200,8n1,amt

Signed-off-by: James Mckenzie <jamesmck@bob.uk.xensource.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Tom Goetz <tom.goetz@virtualcomputer.com>
xen/drivers/char/ns16550.c

index c360ee70f553b52a95a3defcd999e55baf788668..db39f246c1ffa52797905246531c90432cf1334a 100644 (file)
@@ -17,6 +17,8 @@
 #include <xen/timer.h>
 #include <xen/serial.h>
 #include <xen/iocap.h>
+#include <xen/pci.h>
+#include <xen/pci_regs.h>
 #include <asm/io.h>
 
 /*
@@ -440,6 +442,64 @@ static int __init check_existence(struct ns16550 *uart)
     return (status == 0x90);
 }
 
+static int
+magic_uart_config (struct ns16550 *uart,int skip_amt)
+{
+  uint16_t class;
+  uint32_t bar0, len;
+  int b, d, f;
+
+/*Skanky hack - start at bus 1 to avoid AMT, a plug in card cannot be on bus 1 */
+
+  if (skip_amt) b=1;
+       else b=0;
+
+  for (; b < 0x100; ++b)
+    {
+    for (d = 0; d < 0x20; ++d)
+        {
+          for (f = 0; f < 0x8; ++f)
+            {
+
+              class = pci_conf_read16 (b, d, f, PCI_CLASS_DEVICE);
+              if (class != 0x700)
+                continue;;
+
+              bar0 = pci_conf_read32 (b, d, f, PCI_BASE_ADDRESS_0);
+
+              /* Not IO */
+              if (!(bar0 & 1))
+                continue;
+
+              pci_conf_write32 (b, d, f, PCI_BASE_ADDRESS_0, 0xffffffff);
+              len = pci_conf_read32 (b, d, f, PCI_BASE_ADDRESS_0);
+              pci_conf_write32 (b, d, f, PCI_BASE_ADDRESS_0, bar0);
+
+              /* Not 8 bytes */
+              if ((len & 0xffff) != 0xfff9)
+                continue;
+
+              uart->io_base = bar0 & 0xfffe;
+              uart->irq = 0;
+
+              return 0;
+
+            }
+
+        }
+    }
+
+  if (!skip_amt)
+       return -1;
+
+  uart->io_base = 0x3f8;
+  uart->irq = 0;
+  uart->clock_hz  = UART_CLOCK_HZ;
+
+  return 0;
+}
+
+
 #define PARSE_ERR(_f, _a...)                 \
     do {                                     \
         printk( "ERROR: " _f "\n" , ## _a ); \
@@ -488,7 +548,18 @@ static void __init ns16550_parse_port_config(
     if ( *conf == ',' )
     {
         conf++;
-        uart->io_base = simple_strtoul(conf, &conf, 0);
+        
+        if ( strncmp(conf,"magic",5) == 0 ) {
+           if (magic_uart_config(uart,1)) 
+               return;
+           conf+=5;
+        } else if ( strncmp(conf,"amt",3) == 0 ) {
+           if (magic_uart_config(uart,0)) 
+               return;
+           conf+=3;
+        } else {
+            uart->io_base = simple_strtoul(conf, &conf, 0);
+        }
 
         if ( *conf == ',' )
         {